﻿using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.IO;
using System.Text;
using System.Collections.Generic;
using Multiplicity.Runtime.Serialization.Binary;

namespace Multiplicity.Reflection.Tests {
    [TestClass()]
    public class BinaryParserTest {

        private TestContext testContextInstance;

        public TestContext TestContext {
            get {
                return testContextInstance;
            }
            set {
                testContextInstance = value;
            }
        }

        T Read<T>(byte[] data) where T : class, new()  {
            BinaryParser p = new BinaryParser(new BufferSegment( data));
            return p.ReadRecord<T>();
        }

        [TestMethod]
        public void Pack() {

            byte[] data = new byte[] {
                1, 0, 0, 0, 0,
                2, 2, 0, 0, 0,
                4, 4, 4, 4, 0,
                0, 0, 0, 0, 0
            };

            Pak p = Read<Pak>(data);

            Assert.IsNotNull(p);
            Assert.AreEqual((byte)0x0, p.last);
            Assert.AreEqual((byte)0x1, p.b);
            Assert.AreEqual((ushort)0x0202u, p.u16);
            Assert.AreEqual((uint)0x04040404u, p.u32);
            
        }

        [BinaryRecord(Pack=5)]
        class Pak {
            public byte b = 0;
            public ushort u16 = 0;
            public uint u32 = 0;
            public byte last = 0xff;
        }

        [TestMethod]
        public void MagicSignature() {
            byte[] positive = new byte[] {
                42,
            };

            Magie m = Read<Magie>(positive);

            Assert.IsNotNull(m);

            try {
                byte[] negative = new byte[] {
                    23
                };

                m = Read<Magie>(negative);

                Assert.Fail();
            }
            catch (BinaryParserException bpexc) {

                TestContext.WriteLine(bpexc.ToString());

            }
        }

        [BinaryRecord]
        public class Magie {
            [MagicSignature(42)]
            public byte Signature;
        }

        [TestMethod]
        public void BinaryRecord() {

            Version expectedVersion = new Version(1, 2, 3);
            DateTime expectedTime = DateTime.Now;

            uint ut = UnixTime.FromDateTime(expectedTime);

            byte[] data = new byte[] {
                0x1,0x1,0x1,0x1,
                0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4,
                (byte)'A', (byte)'H', (byte)'0', (byte)'J', 0,
                (byte)'Z', (byte)'Z', 0, 0, 0, 0,

                0x1,0,  0x2,0,  0x3,0,

                (byte)((ut & 0xff)),
                (byte)((ut >> 8) & 0xff) ,
                (byte)((ut >> 16) & 0xff),
                (byte)((ut >> 24) & 0xff),
            };

            Rekord s = Read<Rekord>(data);

            Assert.IsNotNull(s);
            Assert.AreEqual(0x01010101u, s.UInt);
            Assert.AreEqual(0x0404040404040404, s.Long);
            Assert.AreEqual("AH0J", s.AsciiZ);
            Assert.AreEqual("ZZ", s.AsciiFixed);
            Assert.AreEqual(expectedVersion, s.Version);
            Assert.IsTrue(Math.Abs((expectedTime - s.UnixTime).TotalSeconds) <= 1);
        }

        [BinaryRecord]
        public class Rekord {

            public uint UInt;
            public long Long;
            
            [BinaryField(BinaryFieldType.StringAsciiZ)]
            public string AsciiZ;

            [BinaryField(BinaryFieldType.StringAsciiZ, FixedLength=6)]
            public string AsciiFixed;

            [VersionField(3, TypeCode.UInt16)]
            public Version Version;

            [BinaryField(BinaryFieldType.UnixTime)]
            public DateTime UnixTime;

        }

    }


}
